%{
#define _BSD_SOURCE
//#include <stdio.h>

#include <string.h>
#include <stdlib.h>
//#include <stdarg.h>

//#define ECHO yyextra->y = yytext; while(*yyextra->y) *(yyextra->b++) = *(yyextra->y++)


struct T {
};

typedef unsigned char uchar;
typedef unsigned long ulong;

#define b00001111 0x0F
#define b00011111 0x1F
#define b00111111 0x3F
#define b11000000 0xC0
#define b11100000 0xE0
#define b10000000 0x80

#define b111      0x07
#define b111111   0x3F
#define b1111     0x0F

//#define b11 0x03

#define YY_EXTRA_TYPE struct Buffer *

#define ECHO yyextra->y = yytext; while(*yyextra->y) *(yyextra->b++) = *(yyextra->y++)
#define putchar(x) *(yyextra->b++) = x

struct Buffer {
	char *buf;
	char *b, *y;
};

%}

%option 8bit
%option noyywrap
%option reentrant
%option prefix="unescape"

%x code

%%

("\\"|"%")"u"  BEGIN(code);




<code>[0-9a-fA-F]{4}  {
							uchar l = strtol(yytext+2, NULL, 16);
							yytext[2] = 0;
							uchar h = strtol(yytext, NULL, 16);
							ulong n = ((ulong)h << 8) + l;
							//fprintf(stderr, "[n=%d, h=%d, l=%d]\n", n, h, l);
							
							if (n <= 0x7F) 
								putchar(n);
							else if (n <= 0x7FF) {
								//fprintf(stderr, "[2:n=%d]\n", n);
								
								putchar(b11000000 | (h << 2) | (l >> 6));
								putchar(b10000000 | (l & b111111));
								
								
								//putchar(b11000000 | ((h & b111) << 3) | (l >> 6));
								//putchar(b10000000 | (l & b111111));
							} else {
								//fprintf(stderr, "[3:n=%d]\n", n);
								putchar(b11100000 | (h >> 4));
								putchar(b10000000 | ((h & b1111) << 2) | (l >> 6));
								putchar(b10000000 | (l & b111111));
							}
							BEGIN(INITIAL);
					  }

%%

char *unescape(const char *str) {
	char *buf = (char *)malloc(strlen(str));
	struct Buffer *oB = (struct Buffer *)malloc(sizeof(struct Buffer));
	oB->buf = buf;
	oB->b = buf;
		
	yyscan_t scanner;
	yylex_init(&scanner);

	yyset_extra(oB, scanner);
	YY_BUFFER_STATE s = yy_scan_string(str, scanner);
	yy_switch_to_buffer(s, scanner);
	
	yylex(scanner);
	yylex_destroy(scanner);
	
	*oB->b = 0;
	
	return buf;
}


